package com.hzyl.famousreader.view.widget.core.loader;

import android.support.annotation.Nullable;
import com.blankj.utilcode.util.ThreadUtils;
import com.hzyl.famousreader.view.widget.core.Charset;
import com.hzyl.famousreader.view.widget.core.model.Chapter;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 完整书籍加载器
 */
public class CompleteDataLoader extends DataLoader {

  private File bookFile;

  //章节解析模式
  private Pattern mChapterPattern = null;

  //默认从文件中获取数据的长度
  private final static int BUFFER_SIZE = 512 * 1024;
  //没有标题的时候，每个章节的最大长度
  private final static int MAX_LENGTH_WITH_NO_CHAPTER = 10 * 1024;

  // "序(章)|前言"
  private final static Pattern mPreChapterPattern = Pattern.compile("^(\\s{0,10})((\u5e8f[\u7ae0\u8a00]?)|(\u524d\u8a00)|(\u6954\u5b50))(\\s{0,10})$", Pattern.MULTILINE);

  //正则表达式章节匹配模式
  // "(第)([0-9零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,10})([章节回集卷])(.*)"
  private static final String[] CHAPTER_PATTERNS = new String[]{"^(.{0,8})(\u7b2c)([0-9\u96f6\u4e00\u4e8c\u4e24\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u58f9\u8d30\u53c1\u8086\u4f0d\u9646\u67d2\u634c\u7396\u62fe\u4f70\u4edf]{1,10})([\u7ae0\u8282\u56de\u96c6\u5377])(.{0,30})$",
    "^(\\s{0,4})([\\(\u3010\u300a]?(\u5377)?)([0-9\u96f6\u4e00\u4e8c\u4e24\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u58f9\u8d30\u53c1\u8086\u4f0d\u9646\u67d2\u634c\u7396\u62fe\u4f70\u4edf]{1,10})([\\.:\uff1a\u0020\f\t])(.{0,30})$",
    "^(\\s{0,4})([\\(\uff08\u3010\u300a])(.{0,30})([\\)\uff09\u3011\u300b])(\\s{0,2})$",
    "^(\\s{0,4})(\u6b63\u6587)(.{0,20})$",
    "^(.{0,4})(BookChapter|chapter)(\\s{0,4})([0-9]{1,4})(.{0,30})$"};

  public CompleteDataLoader(String filePath, Integer chapterPos, Integer pagePos) {
    this.curChapterPagePos = pagePos == null ? 0 : pagePos;
    this.curChapterPos = chapterPos == null ? 0 : chapterPos;
    bookFile = new File(filePath);
    analyze(bookFile);
  }

  @Override
  public BufferedReader openChapter(Chapter chapter) throws IOException {
    try (RandomAccessFile randomAccessFile = new RandomAccessFile(bookFile, "r")) {
      //从指定位置读取章节内容
      randomAccessFile.seek(chapter.getStart());
      int extent = (int) (chapter.getEnd() - chapter.getStart());
      byte[] content = new byte[extent];
      randomAccessFile.read(content, 0, extent);

      //返回字符读写流
      return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(content), mCharset.getName()));
    }
  }

  /**
   * 1. 检查文件中是否存在章节名
   * 2. 判断文件中使用的章节名类型的正则表达式
   *
   * @return 是否存在章节名
   */
  protected boolean checkChapterType(RandomAccessFile bookStream) throws IOException {
    //首先获取128k的数据
    byte[] buffer = new byte[BUFFER_SIZE / 4];
    int length = bookStream.read(buffer, 0, buffer.length);
    //进行章节匹配
    for (String str : CHAPTER_PATTERNS) {
      Pattern pattern = Pattern.compile(str, Pattern.MULTILINE);
      Matcher matcher = pattern.matcher(new String(buffer, 0, length, mCharset.getName()));
      //如果匹配存在，那么就表示当前章节使用这种匹配方式
      if (matcher.find()) {
        mChapterPattern = pattern;
        //重置指针位置
        bookStream.seek(0);
        return true;
      }
    }

    //重置指针位置
    bookStream.seek(0);
    return false;
  }

  /**
   * 分析书本，仅本地有
   * @param file 待分析的对象
   * @return 分析的结果（书籍的章节信息）
   */
  private List<Chapter> analyze(File file) {
    try (RandomAccessFile bookStream = new RandomAccessFile(file, "r")) {
      List<Chapter> tmpChapters = new ArrayList<>();
      //获取文件流

      //寻找匹配文章标题的正则表达式，判断是否存在章节名
      boolean hasChapter = checkChapterType(bookStream);
      //加载章节
      byte[] buffer = new byte[BUFFER_SIZE];
      //获取到的块起始点，在文件中的位置
      long curOffset = 0;
      //block的个数
      int blockPos = 0;
      //读取的长度
      int length;

      //获取文件中的数据到buffer，直到没有数据为止
      while ((length = bookStream.read(buffer, 0, buffer.length)) > 0) {
        ++blockPos;
        //如果存在Chapter
        if (hasChapter) {
          //将数据转换成String
          String blockContent = new String(buffer, 0, length, mCharset.getName());
          //当前Block下使过的String的指针
          int seekPos = 0;
          //进行正则匹配
          Matcher matcher = mChapterPattern.matcher(blockContent);
          //如果存在相应章节
          while (matcher.find()) {
            //获取匹配到的字符在字符串中的起始位置
            int chapterStart = matcher.start();

            //如果 seekPos == 0 && nextChapterPos != 0 表示当前block处前面有一段内容
            //第一种情况一定是序章 第二种情况可能是上一个章节的内容
            if (seekPos == 0 && chapterStart != 0) {
              //获取当前章节的内容
              String chapterContent = blockContent.substring(seekPos, chapterStart);
              //设置指针偏移
              seekPos += chapterContent.length();

              //如果当前对整个文件的偏移位置为0的话，那么就是序章
              if (curOffset == 0) {
                //创建序章
                Chapter preChapter = new Chapter();
                preChapter.setTitle("序章");
                preChapter.setStart(0);
                preChapter.setEnd(chapterContent.getBytes(mCharset.getName()).length); //获取String的byte值,作为最终值

                //如果序章大小大于30才添加进去
                if (preChapter.getEnd() - preChapter.getStart() > 30) {
                  tmpChapters.add(preChapter);
                }

                //创建当前章节
                Chapter curChapter = new Chapter();
                curChapter.setTitle(matcher.group());
                curChapter.setStart(preChapter.getEnd());
                tmpChapters.add(curChapter);
              }
              //否则就block分割之后，上一个章节的剩余内容
              else {
                //获取上一章节
                Chapter lastChapter = tmpChapters.get(tmpChapters.size() - 1);
                //将当前段落添加上一章去
                lastChapter.setEnd(lastChapter.getEnd() + chapterContent.getBytes(mCharset.getName()).length);

                //如果章节内容太小，则移除
                if (lastChapter.getEnd() - lastChapter.getStart() < 30) {
                  tmpChapters.remove(lastChapter);
                }

                //创建当前章节
                Chapter curChapter = new Chapter();
                curChapter.setTitle(matcher.group());
                curChapter.setStart(lastChapter.getEnd());
                tmpChapters.add(curChapter);
              }
            } else {
              //是否存在章节
              if (tmpChapters.size() != 0) {
                //获取章节内容
                String chapterContent = blockContent.substring(seekPos, matcher.start());
                seekPos += chapterContent.length();

                //获取上一章节
                Chapter lastChapter = tmpChapters.get(tmpChapters.size() - 1);
                lastChapter.setEnd(lastChapter.getStart() + chapterContent.getBytes(mCharset.getName()).length);

                //如果章节内容太小，则移除
                if (lastChapter.getEnd() - lastChapter.getStart() < 30) {
                  tmpChapters.remove(lastChapter);
                }

                //创建当前章节
                Chapter curChapter = new Chapter();
                curChapter.setTitle(matcher.group());
                curChapter.setStart(lastChapter.getEnd());
                tmpChapters.add(curChapter);
              }
              //如果章节不存在则创建章节
              else {
                Chapter curChapter = new Chapter();
                curChapter.setTitle(matcher.group());
                curChapter.setStart(0);
                tmpChapters.add(curChapter);
              }
            }
          }
        }
        //进行本地虚拟分章
        else {
          //章节在buffer的偏移量
          int chapterOffset = 0;
          //当前剩余可分配的长度
          int strLength = length;
          //分章的位置
          int chapterPos = 0;

          while (strLength > 0) {
            ++chapterPos;
            //是否长度超过一章
            if (strLength > MAX_LENGTH_WITH_NO_CHAPTER) {
              //在buffer中一章的终止点
              int end = length;
              //寻找换行符作为终止点
              for (int i = chapterOffset + MAX_LENGTH_WITH_NO_CHAPTER; i < length; ++i) {
                if (buffer[i] == Charset.BLANK) {
                  end = i;
                  break;
                }
              }
              Chapter chapter = new Chapter();
              chapter.setTitle("第" + blockPos + "章" + "(" + chapterPos + ")");
              chapter.setStart(curOffset + chapterOffset + 1);
              chapter.setEnd(curOffset + end);
              tmpChapters.add(chapter);
              //减去已经被分配的长度
              strLength = strLength - (end - chapterOffset);
              //设置偏移的位置
              chapterOffset = end;
            } else {
              Chapter chapter = new Chapter();
              chapter.setTitle("第" + blockPos + "章" + "(" + chapterPos + ")");
              chapter.setStart(curOffset + chapterOffset + 1);
              chapter.setEnd(curOffset + length);
              tmpChapters.add(chapter);
              strLength = 0;
            }
          }
        }

        //block的偏移点
        curOffset += length;

        if (hasChapter) {
          //设置上一章的结尾
          Chapter lastChapter = tmpChapters.get(tmpChapters.size() - 1);
          lastChapter.setEnd(curOffset);
        }

        //当添加的block太多的时候，执行GC
        if (blockPos % 15 == 0) {
          System.gc();
          System.runFinalization();
        }
      }

      return tmpChapters;
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }

    //开启清理垃圾线程
    ThreadUtils.executeByIo(new ThreadUtils.SimpleTask<Void>() {
      @Nullable
      @Override
      public Void doInBackground() throws Throwable {
        System.gc();
        System.runFinalization();
        return null;
      }

      @Override
      public void onSuccess(@Nullable Void result) {

      }
    });

    return Collections.EMPTY_LIST;
  }
}
